package fi.iki.juri.units.generator;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Stack;

public class GeneratorTools {
	private static final HashSet<String> OPERATORS = new HashSet<String>();
	static {
		OPERATORS.add("*");
		OPERATORS.add("/");
		OPERATORS.add("+");
		OPERATORS.add("-");
	}
	
	/**
	 * Converts the given postfix expression into infix. The returned value is
	 * supposed to be used in a programming language; obviously this format
	 * won't work in all programming languages, but it does work in Java and
	 * Python.
	 * 
	 * @param expr The postfix expression. Must be balanced: the number of numbers and variables must be two times the number of operators.
	 * @param var The variable used in the expression.
	 * @return The expression converted into infix.
	 * @throws ExpressionConversionException If the expression isn't balanced.
	 */
	public static String postfix2infix(final String expr, final String var) throws ExpressionConversionException {
		String[] splitExpr = expr.split(" ");
		final Stack<String> ifparts = new Stack<String>();
		for (final String sube : splitExpr) {
			if (sube.length() == 0)
				continue;
			if (OPERATORS.contains(sube)) {
				if (ifparts.isEmpty())
					throw new ExpressionConversionException(String.format("Couldn't convert postfix to infix: stack empty when trying to get first operand for operator %s in expression %s", sube, expr));
				final String p1 = ifparts.pop();
				if (ifparts.isEmpty())
					throw new ExpressionConversionException(String.format("Couldn't convert postfix to infix: stack empty when trying to get second operand for operator %s in expression %s", sube, expr));
				final String p2 = ifparts.pop();
				ifparts.push(String.format("(%s %s %s)", p2, sube, p1));
			} else {
				ifparts.push(sube.equals(var) ? sube : Double.valueOf(sube).toString());
			}
		}
		final StringBuilder sb = new StringBuilder(expr.length() * 2);
		for (final String ifpart : ifparts) {
			sb.append(ifpart);
			sb.append(" ");
		}
		return sb.toString().trim();
	}

	public static String reverseExpression(final String expression) {
		if (expression == null)
			throw new IllegalArgumentException("expression may not be null");
		final String[] splitExpr = expression.split(" ");
		final ArrayList<String> reversed = new ArrayList<String>();
		for (final String sube : splitExpr) {
			if (sube.length() == 0)
				continue;
			if ("+".equals(sube))
				reversed.add("-");
			else if ("-".equals(sube))
				reversed.add("+");
			else if ("*".equals(sube))
				reversed.add("/");
			else if ("/".equals(sube))
				reversed.add("*");
			else
				reversed.add(sube);
		}
		final StringBuilder sb = new StringBuilder(expression.length());
		for (final String r : reversed) {
			sb.append(r);
			sb.append(" ");
		}
		return sb.toString().trim();
	}
}
